/**
*
* Copyright (c) 2009-2016 Freedomotic team http://freedomotic.com
*
* This file is part of Freedomotic
*
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* Freedomotic; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
package com.freedomotic.restapi;
import com.freedomotic.api.*;
import com.freedomotic.exceptions.UnableToExecuteException;
import com.freedomotic.reactions.Command;
import com.freedomotic.restapi.server.FreedomRestServer;
import com.freedomotic.restapi.server.OriginFilter;
import com.freedomotic.util.Info;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.restlet.Application;
import org.restlet.Component;
import org.restlet.Restlet;
import org.restlet.Server;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.Parameter;
import org.restlet.data.Protocol;
import org.restlet.engine.Engine;
import org.restlet.ext.crypto.DigestAuthenticator;
import org.restlet.ext.crypto.DigestVerifier;
import org.restlet.ext.crypto.internal.HttpDigestVerifier;
import org.restlet.ext.simple.HttpServerHelper;
import org.restlet.security.ChallengeAuthenticator;
import org.restlet.security.LocalVerifier;
import org.restlet.security.SecretVerifier;
import org.restlet.security.Verifier;
import static org.restlet.security.Verifier.RESULT_INVALID;
import static org.restlet.security.Verifier.RESULT_VALID;
import org.restlet.util.Series;
/**
*
* @author gpt
*/
public class RestApi extends com.freedomotic.api.Protocol {
int SERVER_PORT = 8111;
Component component;
Restlet rest;
Application app;
private static API freedomoticApi;
public RestApi() {
super("RestApi", "/restapi/restapi-manifest.xml");
setPollingWait(-1);
//Avoid The reset of the logging.
//see Issue Core-132 http://freedomotic.myjetbrains.com/youtrack/issue/Core-132
System.setProperty("java.util.logging.config.file", "none");
}
/**
* Expose Freedomotic APIs as a static reference for restapi internal use
*
* @return the Freedomotic APIs reference
*/
public static API getFreedomoticApi() {
return freedomoticApi;
}
@Override
public void onStart() {
try {
super.onStart();
component = new Component();
component.getClients().add(Protocol.FILE);
//TODO: To test with the restlet 2.1 Maybe the maxTotalConnections could be avoided
// see: http://restlet-discuss.1400322.n2.nabble.com/rejectedExecution-td4513620.html
//component.getServers().add(Protocol.HTTP, SERVER_PORT);
Server server = new Server(Protocol.HTTP, SERVER_PORT);
component.getServers().add(server);
server.getContext().getParameters().add("maxTotalConnections", "50");
//end TODO
// enable SSL
Server SSLserver = new Server(Protocol.HTTPS, configuration.getIntProperty("SSL_PORT", SERVER_PORT + 2 ));
component.getServers().add(SSLserver);
Series<Parameter> parameters = SSLserver.getContext().getParameters();
parameters.add("sslContextFactory", "org.restlet.ext.ssl.PkixSslContextFactory");
// Certificate's data is taken from config file
parameters.add("keystorePath", new File(this.getFile().getParent() + "/data/" + configuration.getStringProperty("KEYSTORE_FILE", "keystore")).getAbsolutePath());
parameters.add("keystorePassword", configuration.getStringProperty("KEYSTORE_PASSWORD", "password"));
parameters.add("keyPassword", configuration.getStringProperty("KEYSTORE_PASSWORD", "password"));
parameters.add("keystoreType", configuration.getStringProperty("KEYSTORE_TYPE", "JKS"));
// end enable SSL
// Engine.getInstance().getRegisteredServers().clear();
// Engine.getInstance().getRegisteredServers().add(new HttpServerHelper(server));
// Engine.getInstance().getRegisteredServers().add(new HttpServerHelper(SSLserver));
component.getClients().add(Protocol.FILE);
OriginFilter originFilter = new OriginFilter(component.getContext().createChildContext(),this);
Application FDapp = new FreedomRestServer(Info.PATHS.PATH_RESOURCES_FOLDER.getAbsolutePath(), component.getContext().createChildContext());
if (getApi().getAuth().isInited()) {
// Instantiates a Verifier of identifier/secret couples based on Freedomotic Auth
Verifier v = new SecretVerifier() {
@Override
public int verify(String identifier, char[] secret) {
if (getApi().getAuth().login(identifier, secret)) {
return RESULT_VALID;
}
return RESULT_INVALID;
}
};
// Guard the restlet with BASIC authentication.
ChallengeAuthenticator guard = new ChallengeAuthenticator(component.getContext().createChildContext(), false, ChallengeScheme.HTTP_BASIC, "testRealm", v);
// WIP: Guard the restlet with DIGEST authentication.
DigestAuthenticator dguard = new DigestAuthenticator(component.getContext().createChildContext(), "DigestRealm", configuration.getStringProperty("DIGEST_SECRET", "s3cr3t"));
dguard.setOptional(true);
// TODO: set proper verifier before enabling DIGEST AUTH.
originFilter.setNext(guard);
guard.setNext(FDapp);
} else {
originFilter.setNext(FDapp);
}
component.getDefaultHost().attachDefault(originFilter);
component.start();
freedomoticApi = getApi();
} catch (Exception ex) {
Logger.getLogger(RestApi.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void onStop() {
try {
component.stop();
} catch (Exception ex) {
Logger.getLogger(RestApi.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
protected void onCommand(Command c) throws IOException, UnableToExecuteException {
}
@Override
protected boolean canExecute(Command c) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
protected void onRun() {
}
@Override
protected void onEvent(EventTemplate event) {
}
}